/**
 * Copyright (C) 2021-2022 maminjie <canpool@163.com>
 * SPDX-License-Identifier: LGPL-2.1
 * Powered by Qt-Advanced-Docking-System
**/

#pragma once

#include "qads_global.h"
#include "dockcontainer.h"
#include "dockwidget.h"
#include "dockfloatingwidget.h"

#include <QByteArray>
#include <QDateTime>
#include <QFlags>
#include <QList>
#include <QMap>
#include <QString>
#include <QStringList>
#include <QPointer>
#include <QtGui/QIcon>
#include <qobjectdefs.h>

QT_BEGIN_NAMESPACE
class QMenu;
class QSettings;
QT_END_NAMESPACE

QADS_BEGIN_NAMESPACE

class DockManagerPrivate;
class DockFloatingWidget;
class DockFloatingWidgetPrivate;
class DockContainer;
class DockContainerPrivate;
class DockOverlay;
class DockTabBar;
class DockTab;
class DockTabPrivate;
class DockPannelPrivate;
class DockIconProvider;
class DockFocusController;

class QADS_EXPORT DockManager : public DockContainer
{
    Q_OBJECT
public:
    using Super = DockContainer;

    enum ViewMenuInsertionOrder {
        MenuSortedByInsertion,
        MenuAlphabeticallySorted
    };

public:
    DockManager(QWidget *parent = nullptr);
    ~DockManager() override;

    DockPannel *addDockWidget(DockWidgetArea area, DockWidget *dockWidget, DockPannel *targetPannel);
    DockPannel *addDockWidget(DockWidgetArea area, DockWidget *dockWidget);
    DockPannel *addDockWidget(DockWidget *dockWidget, DockPannel *targetPannel);
    DockPannel *addDockWidgetToContainer(DockWidgetArea area, DockWidget *dockwidget, DockContainer *container);

    DockWidget *centralWidget() const;
    DockPannel *setCentralWidget(DockWidget *widget);

    QMap<QString, DockWidget *> dockWidgetsMap() const;
    DockWidget *findDockWidget(const QString &objectName) const;
    void removeDockWidget(DockWidget *dockWidget);
    void setDockWidgetFocused(DockWidget *dockWidget);
    void hideManagerAndFloatingWidgets();

    DockFloatingWidget *addDockWidgetFloating(DockWidget *dockWidget);
    const QList<QPointer<DockFloatingWidget> > floatingWidgets() const;

    const QList<DockContainer *> dockContainers() const;

    QAction *addToggleViewActionToMenu(QAction *toggleViewAction, const QString &group = QString(),
                                       const QIcon &groupIcon = QIcon());
    QMenu *viewMenu() const;
    void setViewMenuInsertionOrder(ViewMenuInsertionOrder order);

    DockWidget *focusedDockWidget() const;

    QList<int> splitterSizes(DockPannel *pannel) const;
    void setSplitterSizes(DockPannel *pannel, const QList<int> &sizes);

    unsigned int zOrderIndex() const override;

    QByteArray saveState(int version = 0) const;
    bool restoreState(const QByteArray &state, int version = 0);
    bool isRestoringState() const;

    static DockIconProvider &iconProvider();
    static int startDragDistance();

    void addPerspective(const QString &uniquePrespectiveName);
    void removePerspective(const QString &name);
    void removePerspectives(const QStringList &names);
    QStringList perspectiveNames() const;
    void savePerspectives(QSettings &settings) const;
    void loadPerspectives(QSettings &settings);

signals:
 	/**
     * This signal is emitted if the list of perspectives changed.
     * The list of perspectives changes if perspectives are added, removed
     * or if the perspective list has been loaded
     */
    void perspectiveListChanged();

    /**
     * This signal is emitted if the perspective list has been loaded
     */
    void perspectiveListLoaded();

    /**
     * This signal is emitted if perspectives have been removed
     */
    void perspectivesRemoved();
    /**
     * This signal is emitted, if the dock manager starts opening a
     * perspective.
     * Opening a perspective may take more than a second if there are
     * many complex widgets. The application may use this signal
     * to show some progress indicator or to change the mouse cursor
     * into a busy cursor.
     */
    void openingPerspective(const QString &perspectiveName);
    void perspectiveOpened(const QString &perspectiveName);

    void restoringState();
    void stateRestored();

    void floatingWidgetCreated(DockFloatingWidget *floatingWidget);
    void dockPannelCreated(DockPannel *pannel);
    void dockWidgetAboutToBeRemoved(DockWidget *dockWidget);
    void dockWidgetAdded(DockWidget *dockWidget);
    void dockWidgetRemoved(DockWidget *dockWidget);
    void focusedDockWidgetChanged(DockWidget *old, DockWidget *now);

public Q_SLOTS:
    void openPerspective(const QString &perspectiveName);

protected:
    void registerFloatingWidget(DockFloatingWidget *floatingWidget);
    void removeFloatingWidget(DockFloatingWidget *floatingWidget);
    void registerDockContainer(DockContainer *dockContainer);
    void removeDockContainer(DockContainer *dockContainer);

    DockOverlay *containerOverlay() const;
    DockOverlay *pannelOverlay() const;

    void notifyWidgetOrPannelRelocation(QWidget *droppedWidget);
    void notifyFloatingWidgetDrop(DockFloatingWidget *floatingWidget);

    DockFocusController *dockFocusController() const;
    void restoreHiddenFloatingWidgets();

protected:
    void showEvent(QShowEvent *event) override;
#ifdef Q_OS_LINUX
    bool eventFilter(QObject *obj, QEvent *e) override;
#endif

private:
    DockManagerPrivate *d;
    friend class DockManagerPrivate;
    friend class DockFloatingWidget;
    friend class DockFloatingWidgetPrivate;
    friend class DockContainer;
    friend class DockContainerPrivate;
    friend class DockTabBar;
    friend class DockTab;
    friend class DockPannelPrivate;
    friend class DockTabPrivate;
    friend class DockFloatingDragPreview;
    friend class DockFloatingDragPreviewPrivate;
    friend class DockTitleBar;
}; // class DockManager

QADS_END_NAMESPACE
